package net.chasing.androidbaseconfig.util.permission;

import android.Manifest;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.text.TextUtils;

import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.fragment.app.FragmentActivity;

import com.permissionx.guolindev.PermissionX;

import net.chasing.androidbaseconfig.R;
import net.chasing.androidbaseconfig.util.L;
import net.chasing.androidbaseconfig.util.ObjectCacheUtil;
import net.chasing.androidbaseconfig.widget.dialog.PermissionTipsDialog;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class PermissionUtils {
    public interface GrantedCallBack {
        void callBack(boolean isAllGranted);
    }

    // region 跳转第三方权限配置界面
    public static void jumpPermissionPage(Context context) {
        try {
            String name = Build.MANUFACTURER;
            switch (name) {
                case "HUAWEI":
                    goHuaWeiManager(context.getPackageName(), context);
                    break;
                case "vivo":
                    goVivoManager(context);
                    break;
                case "OPPO":
                    goOppoManager(context);
                    break;
                case "Coolpad":
                    goCoolpadManager(context);
                    break;
                case "Meizu":
                    goMeiZuManager(context.getPackageName(), context);
                    break;
                case "Xiaomi":
                    goXiaoMiMainager(context.getPackageName(), context);
                    break;
                case "samsung":
                    goSangXinManager(context.getPackageName(), context);
                    break;
                case "Sony":
                    goSonyManager(context.getPackageName(), context);
                    break;
                case "LG":
                    goLGManager(context.getPackageName(), context);
                    break;
                default:
                    goIntentSetting(context.getPackageName(), context);
                    break;
            }
        } catch (Exception e) {
            goIntentSetting(context.getPackageName(), context);
        }
    }

    private static void goLGManager(String packageName, Context context) {
        try {
            Intent intent = new Intent(packageName);
            ComponentName comp = new ComponentName("com.android.settings", "com.android.settings.Settings$AccessLockSummaryActivity");
            intent.setComponent(comp);
            context.startActivity(intent);
        } catch (Exception e) {
            goIntentSetting(packageName, context);
        }
    }

    private static void goSonyManager(String packageName, Context context) {
        try {
            Intent intent = new Intent(packageName);
            ComponentName comp = new ComponentName("com.sonymobile.cta", "com.sonymobile.cta.SomcCTAMainActivity");
            intent.setComponent(comp);
            context.startActivity(intent);
        } catch (Exception e) {
            goIntentSetting(packageName, context);
        }
    }

    private static void goHuaWeiManager(String packageName, Context context) {
        try {
            Intent intent = new Intent(packageName);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            ComponentName comp = new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity");
            intent.setComponent(comp);
            context.startActivity(intent);
        } catch (Exception e) {
            goIntentSetting(packageName, context);
        }
    }

    private static String getMiuiVersion() {
        String propName = "ro.miui.ui.version.name";
        String line = null;
        BufferedReader input = null;
        try {
            Process p = Runtime.getRuntime().exec("getprop " + propName);
            input = new BufferedReader(
                    new InputStreamReader(p.getInputStream()), 1024);
            line = input.readLine();
        } catch (Exception ex) {
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                }
            }
        }
        return line;
    }

    private static void goXiaoMiMainager(String packageName, Context context) {
        String rom = getMiuiVersion();
        Intent intent = new Intent();
        if ("V6".equals(rom) || "V7".equals(rom)) {
            intent.setAction("miui.intent.action.APP_PERM_EDITOR");
            intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
            intent.putExtra("extra_pkgname", packageName);
            context.startActivity(intent);
        } else if ("V8".equals(rom) || "V9".equals(rom)) {
            intent.setAction("miui.intent.action.APP_PERM_EDITOR");
            intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
            intent.putExtra("extra_pkgname", packageName);
            context.startActivity(intent);
        } else {
            goIntentSetting(packageName, context);
        }

    }

    private static void goMeiZuManager(String packageName, Context context) {
        try {
            Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC");
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.putExtra("packageName", packageName);
            context.startActivity(intent);
        } catch (ActivityNotFoundException localActivityNotFoundException) {
            localActivityNotFoundException.printStackTrace();
            goIntentSetting(packageName, context);
        }
    }

    private static void goSangXinManager(String packageName, Context context) {
        //三星4.3可以直接跳转
        goIntentSetting(packageName, context);
    }

    private static void goIntentSetting(String packageName, Context context) {
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", context.getPackageName(), null);
        intent.setData(uri);
        try {
            context.startActivity(intent);
        } catch (Exception e) {
        }
    }

    private static void goOppoManager(Context context) {
//        doStartApplicationWithPackageName("com.coloros.safecenter",context);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // For Android 8.0 and above
            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            Uri uri = Uri.fromParts("package", "com.superrabbit.pdf", null);
            intent.setData(uri);
            context.startActivity(intent);
        } else {
            // For Android 7.1 and below
            Intent intent = new Intent(Settings.ACTION_APPLICATION_SETTINGS);
            context.startActivity(intent);
        }

    }

    /**
     * doStartApplicationWithPackageName("com.yulong.android.security:remote")
     * 和Intent open = getPackageManager().getLaunchIntentForPackage("com.yulong.android.security:remote");
     * startActivity(open);
     * 本质上没有什么区别，通过Intent open...打开比调用doStartApplicationWithPackageName方法更快，也是android本身提供的方法
     */
    private static void goCoolpadManager(Context context) {
        doStartApplicationWithPackageName("com.yulong.android.security:remote", context);
      /*  Intent openQQ = getPackageManager().getLaunchIntentForPackage("com.yulong.android.security:remote");
        startActivity(openQQ);*/
    }

    private static void goVivoManager(Context context) {
        doStartApplicationWithPackageName("com.bairenkeji.icaller", context);
     /*   Intent openQQ = getPackageManager().getLaunchIntentForPackage("com.vivo.securedaemonservice");
        startActivity(openQQ);*/
    }

    private static void doStartApplicationWithPackageName(String packagename, Context context) {
        // 通过包名获取此APP详细信息，包括Activities、services、versioncode、name等等
        PackageInfo packageinfo = null;
        try {
            packageinfo = context.getPackageManager().getPackageInfo(packagename, 0);
        } catch (PackageManager.NameNotFoundException e) {

        }
        if (packageinfo == null) {
            return;
        }
        try {
            // 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent
            Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
            resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
            resolveIntent.setPackage(packageinfo.packageName);
            // 通过getPackageManager()的queryIntentActivities方法遍历
            List<ResolveInfo> resolveinfoList = context.getPackageManager().queryIntentActivities(resolveIntent, 0);
            ResolveInfo resolveinfo = resolveinfoList.iterator().next();
            if (resolveinfo != null) {
                // packageName参数2 = 参数 packname
                String packageName = resolveinfo.activityInfo.packageName;
                // 这个就是我们要找的该APP的LAUNCHER的Activity[组织形式：packageName参数2.mainActivityname]
                String className = resolveinfo.activityInfo.name;
                // LAUNCHER Intent
                Intent intent = new Intent(Intent.ACTION_MAIN);
                intent.addCategory(Intent.CATEGORY_LAUNCHER);
                // 设置ComponentName参数1:packageName参数2:MainActivity路径
                ComponentName cn = new ComponentName(packageName, className);
                intent.setComponent(cn);
                context.startActivity(intent);
            }
        } catch (Exception e) {
            goIntentSetting(packagename, context);
        }
    }
    // endregion

    /**
     * @param checkFirstTag 用来判断是否弹窗提示过，用户点击行为进行申请权限的，该值传空
     *                      非用户行为进行申请权限的，必须传该值，华为上架不允许第二次自动弹窗申请权限
     */
    private static void requestPermission(FragmentActivity activity, String checkFirstTag,
                                          GrantedCallBack grantedCallBack, String... permissionList) {
        if (isRequesting) return;
        boolean canShowDialog;
        if (!TextUtils.isEmpty(checkFirstTag)) {
            // 不需要点击就进行弹窗获取权限的，只能进行一次，后续用户手动点击申请权限的才允许弹窗
            canShowDialog = (boolean) ObjectCacheUtil.readObject(activity, checkFirstTag, true);
        } else {
            canShowDialog = true;
        }

        PermissionX.init(activity).permissions(permissionList)
                .explainReasonBeforeRequest()
                .onExplainRequestReason((scope, deniedList, beforeRequest) -> {
                    if (beforeRequest && canShowDialog) {
                        if (!TextUtils.isEmpty(checkFirstTag))
                            ObjectCacheUtil.saveObject(activity, checkFirstTag, false);

                        boolean hadAddStorage = false;
                        boolean hadAddCalendar = false;
                        boolean hadAddAudio = false;
                        StringBuilder tipMsg = new StringBuilder();
                        for (String per : deniedList) {
                            switch (per) {
                                case Manifest.permission.WRITE_EXTERNAL_STORAGE:
                                case Manifest.permission.READ_EXTERNAL_STORAGE:
                                case Manifest.permission.READ_MEDIA_IMAGES:
                                case Manifest.permission.READ_MEDIA_VIDEO:
                                case Manifest.permission.READ_MEDIA_AUDIO:
                                    if (!hadAddStorage) {
                                        hadAddStorage = true;
                                        tipMsg.append(activity.getString(R.string.base_permission_write_external_tip)).append("\n");
                                    }
                                    break;

                                case Manifest.permission.CAMERA:
                                    tipMsg.append(activity.getString(R.string.base_permission_camera_tip)).append("\n");
                                    break;

                                case Manifest.permission.CALL_PHONE:
                                    tipMsg.append(activity.getString(R.string.base_permission_call_phone_tip)).append("\n");
                                    break;

                                case Manifest.permission.WRITE_CALENDAR:
                                case Manifest.permission.READ_CALENDAR:
                                    if (!hadAddCalendar) {
                                        hadAddCalendar = true;
                                        tipMsg.append(activity.getString(R.string.base_permission_write_calendar_tip)).append("\n");
                                    }
                                    break;

                                case Manifest.permission.MODIFY_AUDIO_SETTINGS:
                                case Manifest.permission.RECORD_AUDIO:
                                    if (!hadAddAudio) {
                                        hadAddAudio = true;
                                        tipMsg.append(activity.getString(R.string.base_permission_record_audio_tip)).append("\n");
                                    }
                                    break;
                            }
                        }
                        if (tipMsg.length() > 0)
                            tipMsg.deleteCharAt(tipMsg.length() - 1);
                        PermissionTipsDialog dialog = new PermissionTipsDialog(activity);
                        dialog.setTips(tipMsg.toString());
                        dialog.setPermissionList(deniedList);
                        scope.showRequestReasonDialog(dialog);
                    }
                })
                .onForwardToSettings((scope, deniedList) -> {
                    PermissionTipsDialog dialog = new PermissionTipsDialog(activity);
                    dialog.setTips(activity.getString(R.string.manually_enable_permissions));
                    dialog.setLeftText(activity.getString(R.string.ignore));
                    dialog.getPositiveButton().setOnClickListener(view -> jumpPermissionPage(activity));
                    dialog.setRightText(activity.getString(R.string.go_setting));
                    dialog.setPermissionList(deniedList);
                    scope.showForwardToSettingsDialog(dialog);
                })
                .request((allGranted, grantedList, deniedList) -> {
                    if (grantedCallBack != null) {
                        grantedCallBack.callBack(allGranted);
                    }
                    isRequesting = false;
                });
    }

    // 进行检测是否拥有权限
    public static boolean checkPermissions(Activity activity, String... permission) {
        for (String per : permission) {
            if (ActivityCompat.checkSelfPermission(activity, per) != PackageManager.PERMISSION_GRANTED) {
                L.i("需要申请：" + per);
                return false;
            }
        }
        return true;
    }

    // 请求权限，返回是否需要请求（注：如果在AndroidManifest.xml里没有申请权限，那这里也不会发起申请）
    public static boolean isRequesting;

    /**
     * 判断是否有权限，没有则进行请求
     *
     * @return true 为没有权限，需要请求 false 有权限，不用发起请求
     */
    public synchronized static boolean requestPermission(FragmentActivity activity,
                                                         GrantedCallBack callBack, String... permission) {
        if (isRequesting) return true;
        List<String> noPermissionList = new ArrayList<>();
        for (String per : permission) {
            if (!checkPermissions(activity, per))
                noPermissionList.add(per);
        }
        if (noPermissionList.isEmpty()) return false;

        requestPermission(activity, null, callBack, permission);
        return true;
    }

    // region 存储权限相关

    /**
     * Android 14新增了READ_MEDIA_VISUAL_USER_SELECTED权限，用于对照片和视频进行选择性授权
     * <p>
     * Android13开始，READ_EXTERNAL_STORAGE被细分成三个权限
     * 而且即使调用了申请Manifest.permission.WRITE_EXTERNAL_STORAGE权限，
     * 也不会拉起授权弹窗，所以后续不需要判断该权限
     * <p>
     * Android11的MANAGE_EXTERNAL_STORAGE管理所有文件权限:
     * Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
     * startActivityForResult(intent, 102);
     */
    public static boolean checkStoragePermission(FragmentActivity activity) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
            return checkPermissions(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.READ_EXTERNAL_STORAGE);
        else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
            return checkPermissions(activity,
                    Manifest.permission.READ_MEDIA_IMAGES,
                    Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.READ_MEDIA_AUDIO);
        else
            return checkPermissions(activity,
                    Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED,
                    Manifest.permission.READ_MEDIA_IMAGES,
                    Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.READ_MEDIA_AUDIO);
    }

    public static boolean requestStoragePermission(FragmentActivity activity, GrantedCallBack callBack) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
            return requestPermission(activity, callBack,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.READ_EXTERNAL_STORAGE);
        else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
            return requestPermission(activity, callBack,
                    Manifest.permission.READ_MEDIA_IMAGES,
                    Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.READ_MEDIA_AUDIO);
        else
            return requestPermission(activity, callBack,
                    Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED,
                    Manifest.permission.READ_MEDIA_IMAGES,
                    Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.READ_MEDIA_AUDIO);
    }

    public static boolean requestStoragePermission(FragmentActivity activity, GrantedCallBack callBack, String permission) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
            return requestPermission(activity, callBack,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.READ_EXTERNAL_STORAGE, permission);
        else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
            return requestPermission(activity, callBack,
                    Manifest.permission.READ_MEDIA_IMAGES,
                    Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.READ_MEDIA_AUDIO, permission);
        else
            return requestPermission(activity, callBack,
                    Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED,
                    Manifest.permission.READ_MEDIA_IMAGES,
                    Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.READ_MEDIA_AUDIO, permission);
    }
    // endregion

    public static boolean isNotificationEnable(Context context) {
        return NotificationManagerCompat.from(context).areNotificationsEnabled();
    }
}
